import cv2
import numpy as np


image_size = 1081
block_count = 9
block_size = image_size // block_count

pi = np.pi
half_pi = pi/2
bit = 16
channel_count = 1
max_color = 1.0 #pow(2, bit)-1
max_height = 1024.0


# def draw_block(img):
#     for i in range(block_count):
#         pos = i*block_size
#         cv2.line(Img, (0, pos), (image_size, pos), height2color(400), 1)
#         cv2.line(Img, (pos, 0), (pos, image_size), height2color(400), 1)


def h2c(h):
    return h/max_height


class Point(object):
    def __init__(self, x, y):
        self.x = int(x)
        self.y = int(y)

    def __add__(self, other):
        return Point(self.x+other.x, self.y+other.y)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y


class MapColor(object):
    def __init__(self, h_begin: float, h_end: float = None, angle: float = 0.0):
        self.h_end = None
        self.h_begin = None
        self.set_value(h_begin, h_end)
        self.slope = angle

    def set_value(self, h_begin: float, h_end: float = None):
        self.h_begin = h_begin
        self.h_end = h_end if h_end is not None else self.h_begin


class Image(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        self.image = np.zeros((self.height, self.width), np.float64)
        self.pos = Point(0, 0)

    def __mul__(self, other):
        new_image = Image(self.width, self.height)
        new_image.image = np.multiply(self.image, other.image)
        return new_image

    def set_pos(self, x, y):
        self.pos.x = int(x)
        self.pos.y = int(y)

    def draw_rect(self, width, height, c: MapColor):
        width = int(width)
        height = int(height)

        total = height * np.sin(c.slope) + width * np.cos(c.slope)
        diff = c.h_begin - c.h_end
        for col in range(width):
            for row in range(height):
                r = row * np.sin(c.slope) + col * np.cos(c.slope)
                c_v = (1-r/total)*diff+c.h_end
                self.image[row+self.pos.y, col + self.pos.x] = c_v if c_v <= max_color else max_color

    def draw_circle(self, radius, c, thickness):
        cv2.circle(self.image, (self.pos.x, self.pos.y), int(radius), c, thickness)

    def draw_circle_with_map_color(self, radius_begin, radius_end, map_color: MapColor):
        temp = Image(self.width, self.height)
        temp.set_pos(self.pos.x, self.pos.y)

        radius_begin = int(radius_begin)
        radius_end = int(radius_end)
        radius_diff = radius_end - radius_begin
        diff = map_color.h_end - map_color.h_begin
        for r in range(radius_end, radius_begin, -1):
            v_c = (r-radius_begin)/radius_diff*diff+map_color.h_begin
            cv2.circle(temp.image, (temp.pos.x, temp.pos.y), int(r), v_c, -1)

        min_radius = radius_begin if radius_begin < radius_end else radius_end
        cv2.circle(temp.image, (temp.pos.x, temp.pos.y), min_radius-1, 0, -1)

        for h in range(self.height):
            for w in range(self.width):
                p1 = self.image[h][w]
                p2 = temp.image[h][w]
                self.image[h][w] = p1 if p2 == 0.0 else p2

    def draw_block(self, c, h_block_count=block_count, v_block_count=block_count):
        h_block_size = self.width/h_block_count
        v_block_size = self.height/v_block_count
        c = int(c)

        for i in range(h_block_count):
            pos = int(i*h_block_size)
            cv2.line(self.image, (pos, 0), (pos, self.height), c, 1)

        for i in range(v_block_count):
            pos = int(i*v_block_size)
            cv2.line(self.image, (0, pos), (self.width, pos), c, 1)

    def show(self, title):
        cv2.imshow(title, self.image)

    def write(self, filename):
        m = np.multiply(self.image, 65535)
        m = m.astype(np.uint16)
        cv2.imwrite(filename, m)


def main():
    base_height = 40
    river_height = 15

    base_map_color = MapColor(h2c(base_height), h2c(0))

    #base_mask = Image(image_size, image_size)
    #base_mask.draw_rect(block_size*9, block_size*9, MapColor(max_color, height2color(0)))

    river = Image(image_size, image_size)
    river.draw_rect(block_size*9, block_size*9, MapColor(max_color))

    # 水平river
    river.set_pos(0, image_size/2-river_height)
    river.draw_rect(block_size*4.5, river_height*2, MapColor(0.0, max_color))

    river.set_pos(image_size/2, image_size/2-river_height)
    river.draw_rect(block_size*4.5, river_height*2, MapColor(max_color, 0.0))
    #垂直 river
    river.set_pos(image_size/2-river_height, 0)
    river.draw_rect(river_height*2, block_size*4.5, MapColor(0.0, max_color, pi/2))

    river.set_pos(image_size/2-river_height, image_size/2)
    river.draw_rect(river_height*2, block_size*4.5, MapColor(max_color, 0.0, pi/2))


    river_mask = Image(image_size, image_size)
    river_mask.draw_rect(block_size*9, block_size*9, MapColor(max_color))
    # 水平river mask
    river_mask.set_pos(0, image_size/2-river_height)
    river_mask.draw_rect(block_size*9, river_height, MapColor(max_color, 0, pi/2))

    river_mask.set_pos(0, image_size/2)
    river_mask.draw_rect(block_size*9, river_height, MapColor(0, max_color, pi/2))

    # 垂直 river mask
    river_mask.set_pos(image_size/2-river_height, 0)
    river_mask.draw_rect(river_height, block_size*9, MapColor(max_color, 0))

    river_mask.set_pos(image_size/2, 0)
    river_mask.draw_rect(river_height, block_size*9, MapColor(0, max_color))

    base_mask = river_mask * river

    base_mask.set_pos(image_size/2, image_size/2)
    base_mask.draw_circle(block_size*0.6, max_color, -1)

    #base_mask.draw_circle_with_map_color(block_size*2, block_size*2.2, MapColor(max_color, max_color))

    base_mask.show('base_mask')

    image = Image(image_size, image_size)
    image.set_pos(0, 0)
    image.draw_rect(block_size*9, block_size*9, MapColor(h2c(base_height+100)))

    # Window name in which image is displayed

    #image.set_pos(0, 0)
    #image.draw_rect(block_size*7, block_size*9, base_map_color)

    mask = Image(image_size, image_size)
    mask.draw_rect(image_size, image_size, MapColor(max_color))
    mask.set_pos(block_size*4.5, block_size*4.5)

    #image.draw_circle(block_size * 2.5*1.1, height2color(100), -1)
    mask.draw_circle_with_map_color(block_size*4, block_size * 4.6, MapColor(0, max_color))
    mask.draw_circle_with_map_color(block_size*3.5, block_size * 4, MapColor(max_color, 0))

    mask.draw_circle_with_map_color(block_size*0.6, block_size*0.7, MapColor(0, max_color))
    mask.draw_circle_with_map_color(block_size*0.5, block_size*0.6, MapColor(max_color, 0))

    mask.draw_circle_with_map_color(block_size*2.1, block_size*2.2, MapColor(0, max_color))
    mask.draw_circle_with_map_color(block_size*2, block_size*2.1, MapColor(max_color, 0))

    mask.show('mask')

    image.set_pos(block_size*4.5, block_size*4.5)
    image.draw_circle_with_map_color(block_size*3, block_size * 3.5,
                                     MapColor(h2c(base_height+200), h2c(base_height+150)))

    image.set_pos(block_size*4.5, block_size*4.5)
    image.draw_circle(block_size * 3, h2c(base_height+200), -1)

    #image.set_pos(0, image_size/2-river_height)
    #image.draw_rect(block_size*9, river_height, MapColor(height2color(base_height), height2color(0), pi/2))
    #image.set_pos(0, image_size/2)
    #image.draw_rect(block_size*9, river_height, MapColor(height2color(0), height2color(base_height), pi/2))

    image.show('image1')
    image = image * mask
    image = image * base_mask



    # river_height = 10
    # image.set_pos(0, image_size/2-river_height/2)
    # image.draw_rect(block_size*8, river_height, MapColor(height2color(base_height)/4, 0))


    # Using cv2.circle() method
    # Draw a circle of red color of thickness -1 px
    #image = cv2.circle(Img, (2*block_size+0, 2*block_size), block_size, height2color(100), -1)


    image.write('b.png')
    image.draw_block(h2c(200))

    image.show('Image')


if __name__ == '__main__':
    #image = Image(image_size, image_size)
    #image.set_pos(image_size/2, image_size/2)
    #image.draw_circle_with_map_color(block_size, block_size*2, MapColor(max_color, max_color/2))
    #image.show('Image')

    main()

    cv2.waitKey(0)
    cv2.destroyAllWindows()



